package cis350.pcr;

import java.util.ArrayList;

import org.apache.http.client.params.ClientPNames;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteConstraintException;
import android.util.Log;
import android.widget.Toast;

import cis350.pcr.activities.ResultActivity;
import cis350.pcr.activities.SearchActivity;
import cis350.pcr.types.Type.SearchType;

import com.loopj.android.http.*;

public class SearchHandler { 
	private final String BASE_URL = "http://api.penncoursereview.com/v1/";
	private final String API_KEY = "?token=573-2_4ykZdNLiHFfc9rehZ9c8fCNg";
	private AsyncHttpClient client = new AsyncHttpClient();
	public SearchDB searchDB;
	public CodeLookupDB codeDB;
	private Context activity;
	public static ArrayList<String> json_data = new ArrayList<String>();;
	public AutoCompleteAdapter adapter;

	private int progress;
	public ProgressDialog loadingDialog;
	
	private ArrayList<String> semesterLabel = new ArrayList<String>();
	private ArrayList<String> semesterData = new ArrayList<String>(); 
	private ArrayList<String> descriptionArray = new ArrayList<String>();
	
	
	public SearchHandler(Context context) {
		searchDB = new SearchDB(context);
		codeDB = new CodeLookupDB(context);
		activity = context;
	}

	/**
	 * 
	 * @param url
	 *            should not start or end with a / ex
	 *            coursehistory/cis-121/reviews
	 * @param params
	 *            null generally unless we want to get fancy
	 * @param responseHandler
	 *            should be some HttpResponseHandler ie JSONHttpResponseHandler
	 *            or HttpResponseHandler
	 */
	public void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
		client.getHttpClient().getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);

		client.get(getAbsoluteUrl(url), params, responseHandler);
	}

	private String getAbsoluteUrl(String relativeUrl) {
		return BASE_URL + relativeUrl + API_KEY;
	}

	private void searchDepartment(final String deptPath, final String term, final AsyncHttpResponseHandler handler) {
		final ArrayList<String> coursePath = new ArrayList<String>();
		codeDB.getCourseinDept(term, coursePath);

		progress = 0;

		for (int i = 0; i < coursePath.size(); i++) {
			final String path = "coursehistories/" + coursePath.get(i) + "/reviews";

			String results = searchDB.getCached(path);
			
			if (results != null) {
				json_data.add(results);
				//getSemesterInfo(results, label, data, description, handler);
				progress++;
				continue;
			}
			
			get(path, null, new AsyncHttpResponseHandler() {
				@Override
				public void onStart() {
					Log.d("Search request Department", "starting");
				}

				@SuppressWarnings("deprecation")
				@Override
				public void onFailure(Throwable e) {
					e.printStackTrace();
					if (handler != null)
						handler.onFailure(e);

					Log.d("Search Request Department", "http failed");
				}

				@Override
				public void onSuccess(String response) {
					Log.d("Search Request Department", "Success");

					searchDB.addCache(path, response);

					progress++;
					json_data.add(response);
					//getSemesterInfo(results, label, data, description, handler);

					
					if (progress == coursePath.size())
						handler.onSuccess("");
				}
			});
		}
		
		if (progress == coursePath.size())
			handler.onSuccess("");
		
	}

	private void searchCourse(final String path, final String term, final ArrayList<String> label,
			final AsyncHttpResponseHandler handler) {
		
		
		String results = searchDB.getCached(path);

		if (results != null) {
			json_data.add(results);
			getSemesterInfo(results, label, descriptionArray, handler);
		}

		get(path, null, new AsyncHttpResponseHandler() {
			@Override
			public void onStart() {
				Log.d("Search request Course", "starting");
			}

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable e) {
				e.printStackTrace();
				if (handler != null)
					handler.onFailure(e);

				Log.d("Search Request Course", "http failed");
			}

			@Override
			public void onSuccess(String response) {
				Log.d("Search Request Course", "Success");

				searchDB.addCache(path, response);

				json_data.add(response);
				getSemesterInfo(response, label, descriptionArray, handler);
			}
		});

	}

	private void searchInstructor(final String path, final String term, final ArrayList<String> label,
			final AsyncHttpResponseHandler handler) {
		
		String results = searchDB.getCached(path);
		
		if (results != null) {
			json_data.add(results);
			getSemesterInfo(results, label, null, handler);
		}

		get(path, null, new AsyncHttpResponseHandler() {
			@Override
			public void onStart() {
				Log.d("Search request Instructor", "starting");
			}

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable e) {
				e.printStackTrace();
				if (handler != null)
					handler.onFailure(e);

				Log.d("Search Request Instructor", "http failed");
			}

			@Override
			public void onSuccess(String response) {
				Log.d("Search Request Instructor", "Success");

				searchDB.addCache(path, response);
				
				json_data.add(response);
				getSemesterInfo(response, label, null, handler);
			}
		});
		
	}

	public void search(final String path, final String term, final SearchType type, final String filter) {
		json_data = new ArrayList<String>();
		
		showLoadingDialog();
		AsyncHttpResponseHandler async = new AsyncHttpResponseHandler() {
			@Override
			public void onFailure(Throwable e) {
				searchFailed("An error occured when searching "+type);
			}

			@Override
			public void onSuccess(String response) {
				goToResults(path, term, type, filter);
			}};
				
		
		searchDB.addRecent(path, term, type);
		
		if (type == SearchType.DEPT)
			searchDepartment(path, term, async);
		else if (type == SearchType.COURSE)
			searchCourse(path, term, semesterLabel, async);
		else if (type == SearchType.INSTRUCTOR)
			searchInstructor(path, term, semesterLabel, async);
		
//		loadingDialog.dismiss();
		stopLoadingDialog();
	}

	private void getSemesterInfo(String JSON, final ArrayList<String> label,
			final ArrayList<String> description, final AsyncHttpResponseHandler handler) {

		try {
			JSONObject toplevel = new JSONObject(JSON);
			final JSONArray courses = toplevel.getJSONObject("result").getJSONArray("values");

			try {
				for (int i = 0; i < courses.length(); i++) {
					JSONObject entry = courses.getJSONObject(i);

					JSONObject section = entry.getJSONObject("section");
					String rawid = section.getString("id");

					final String id = rawid.split("-")[0];
					String path = "courses/" + id;

					String cached = searchDB.getSemester(id);

					if (cached != null) {
						label.add(id);
						semesterData.add(cached);

						String currentDescription = searchDB.getDescription(label.get(i));
						if (description != null && currentDescription != null)
							description.add(currentDescription);

					} else {

						get(path, null, new AsyncHttpResponseHandler() {
							@Override
							public void onStart() {
								Log.d("Search request Semester", "starting " + id);
							}
							
							@Override
							public void onFailure(Throwable e) {
								e.printStackTrace();
								Log.d("error", "http failed");
							}

							public void onSuccess(final String response) {
								label.add(id);
								try {
									JSONObject toplevel = new JSONObject(response);
									JSONObject result = toplevel.getJSONObject("result");
									String semester = result.getString("semester");
									semesterData.add(semester);

									searchDB.addSemester(id, semester);

									String currentDescription = result.getString("description");

									if (description != null && currentDescription != null)
										description.add(currentDescription);

									if (label.size() == courses.length()) {
										if (description != null)
											searchDB.addDescription(id, description.get(description.size() - 1));

										handler.onSuccess("");
									}

								} catch (JSONException e) {
									e.printStackTrace();
								}

							}
						});
					}

				}

				if (label.size() == courses.length()) {
					handler.onSuccess("");
				}

			} catch (SQLiteConstraintException e) {
				e.printStackTrace();
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}

	}

	private void searchFailed(String errMsg) {
//		loadingDialog.dismiss();
		stopLoadingDialog();
		CharSequence text = errMsg+"\nTry searching for something else";
		int duration = Toast.LENGTH_LONG;
		Toast toast = Toast.makeText(activity, text, duration);

		toast.show();
	}

	private void goToResults(String path, String term, SearchType type, String filter) {
		Intent nextScreen = new Intent(activity, ResultActivity.class);

		nextScreen.putExtra("path", path);
		nextScreen.putExtra("search input", term);
		nextScreen.putExtra("description", descriptionArray);
		nextScreen.putExtra("semester label", semesterLabel);
		nextScreen.putExtra("semester data", semesterData);
		nextScreen.putExtra("action title", "");
		nextScreen.putExtra("search type", type);
		nextScreen.putExtra("filter", filter);

//		loadingDialog.dismiss();
		stopLoadingDialog();
		activity.startActivity(nextScreen);	
	}
	
	public void showLoadingDialog() {
		Log.d("Show Loading Dialog", "Loading Dialog should show up");
		loadingDialog = ProgressDialog.show(activity, "", "Loading...");
		loadingDialog.setCancelable(true);	
	}
	
	public void stopLoadingDialog(){
		if (loadingDialog != null && loadingDialog.isShowing()) {
			loadingDialog.dismiss();
			loadingDialog = null;
		}
	}

	
}
